package com.weaver.model;

import java.util.*;
import java.io.*;

/**
 * Model class - Data model for the Weaver game
 * Implements Observable interface to notify observers when model state changes
 */
public class Model extends Observable {
    // 常量
    private static final int WORD_LENGTH = 4;
    private static final String DEFAULT_START_WORD = "HIDE";
    private static final String DEFAULT_TARGET_WORD = "SEEK";

    // 游戏状态
    private String startWord;
    private String targetWord;
    private List<String> attempts;
    private List<String[]> feedbacks;
    private boolean gameWon;

    // 标志
    private boolean showErrorMessage;
    private boolean showPath;
    private boolean useRandomWords;

    // 字典
    private Dictionary dictionary;

    // Last notification argument
    private Object lastNotificationArg;

    /**
     * Notify observers that the model has changed
     * This method calls setChanged() and notifyObservers()
     * @param arg parameter passed to observers
     */
    public void notifyChange(Object arg) {
        this.lastNotificationArg = arg;
        setChanged();
        notifyObservers(arg);
    }

    /**
     * Notify observers that the model has changed
     * This method calls setChanged() and notifyObservers()
     */
    public void notifyChange() {
        setChanged();
        notifyObservers();
    }

    /**
     * Constructor
     */
    public Model() {
        dictionary = new Dictionary();
        attempts = new ArrayList<>();
        feedbacks = new ArrayList<>();
        showErrorMessage = true;
        showPath = false;
        useRandomWords = false;
        initGame();
    }

    /**
     * Initialize the game
     * Set the start word and target word, reset game state
     */
    public void initGame() {
        if (useRandomWords) {
            // 从字典中随机选择起始单词和目标单词
            List<String> fourLetterWords = dictionary.getWordsByLength(WORD_LENGTH);
            if (fourLetterWords.size() >= 2) {
                Random random = new Random();
                startWord = fourLetterWords.get(random.nextInt(fourLetterWords.size()));

                // 确保目标单词与起始单词不同
                do {
                    targetWord = fourLetterWords.get(random.nextInt(fourLetterWords.size()));
                } while (targetWord.equals(startWord));
            } else {
                // 如果字典中没有足够的4字母单词，使用默认值
                startWord = DEFAULT_START_WORD;
                targetWord = DEFAULT_TARGET_WORD;
            }
        } else {
            // 使用默认的起始单词和目标单词
            startWord = DEFAULT_START_WORD;
            targetWord = DEFAULT_TARGET_WORD;
        }

        // 重置游戏状态
        attempts.clear();
        feedbacks.clear();
        gameWon = false;

        // 通知观察者模型已更新
        setChanged();
        notifyObservers();
    }

    /**
     * Try a word
     * @param word the word entered by the player
     * @return true if the word is valid, false otherwise
     */
    public boolean tryWord(String word) {
        // 转换为大写
        word = word.toUpperCase();

        // 检查单词长度
        if (word.length() != WORD_LENGTH) {
            if (showErrorMessage) {
                System.out.println("Word must be " + WORD_LENGTH + " letters");
            }
            return false;
        }

        // 检查是否是有效的单词
        if (!dictionary.isValidWord(word)) {
            if (showErrorMessage) {
                System.out.println("'" + word + "' is not a valid word");
            }
            return false;
        }

        // 检查与前一个单词的差异
        if (!attempts.isEmpty()) {
            String previousWord = attempts.get(attempts.size() - 1);
            if (!isDifferByOneLetter(previousWord, word)) {
                if (showErrorMessage) {
                    System.out.println("You can only change one letter at a time");
                }
                return false;
            }
        } else {
            // 第一次尝试，检查与起始单词的差异
            if (!isDifferByOneLetter(startWord, word)) {
                if (showErrorMessage) {
                    System.out.println("You can only change one letter at a time");
                }
                return false;
            }
        }

        // 添加到尝试列表
        attempts.add(word);

        // 生成反馈
        String[] feedback = generateFeedback(word);
        feedbacks.add(feedback);

        // 检查是否获胜
        if (word.equals(targetWord)) {
            gameWon = true;
        }

        // 通知观察者模型已更新
        setChanged();
        notifyObservers();

        return true;
    }

    /**
     * Generate feedback for a word
     * @param word the word entered by the player
     * @return feedback array, status for each letter:
     *         "correct" - letter is correct and in the correct position
     *         "wrong" - letter is not in the target word
     */
    private String[] generateFeedback(String word) {
        String[] feedback = new String[WORD_LENGTH];

        for (int i = 0; i < WORD_LENGTH; i++) {
            char c = word.charAt(i);
            if (c == targetWord.charAt(i)) {
                feedback[i] = "correct";
            } else {
                feedback[i] = "wrong";
            }
        }

        return feedback;
    }

    /**
     * Check if two words differ by only one letter
     * @param word1 first word
     * @param word2 second word
     * @return true if they differ by only one letter, false otherwise
     */
    private boolean isDifferByOneLetter(String word1, String word2) {
        if (word1.length() != word2.length()) {
            return false;
        }

        int diffCount = 0;
        for (int i = 0; i < word1.length(); i++) {
            if (word1.charAt(i) != word2.charAt(i)) {
                diffCount++;
            }
        }

        return diffCount == 1;
    }

    /**
     * Find a path from the start word to the target word
     * Uses breadth-first search algorithm
     * @return list of words in the path, or empty list if no path is found
     */
    public List<String> findPath() {
        // 如果字典未加载，返回空列表
        if (dictionary.isEmpty()) {
            return new ArrayList<>();
        }

        // 使用广度优先搜索查找路径
        Queue<List<String>> queue = new LinkedList<>();
        Set<String> visited = new HashSet<>();

        // 初始路径包含起始单词
        List<String> initialPath = new ArrayList<>();
        initialPath.add(startWord);
        queue.add(initialPath);
        visited.add(startWord);

        while (!queue.isEmpty()) {
            List<String> path = queue.poll();
            String lastWord = path.get(path.size() - 1);

            // 如果到达目标单词，返回路径
            if (lastWord.equals(targetWord)) {
                return path;
            }

            // 获取所有可能的下一个单词
            List<String> neighbors = getNeighbors(lastWord);
            for (String neighbor : neighbors) {
                if (!visited.contains(neighbor)) {
                    visited.add(neighbor);
                    List<String> newPath = new ArrayList<>(path);
                    newPath.add(neighbor);
                    queue.add(newPath);
                }
            }
        }

        // 如果没有找到路径，返回空列表
        return new ArrayList<>();
    }

    /**
     * Get all possible neighbors of a word (valid words that differ by one letter)
     * @param word the word
     * @return list of neighbors
     */
    private List<String> getNeighbors(String word) {
        List<String> neighbors = new ArrayList<>();

        // 对于单词的每个位置
        for (int i = 0; i < word.length(); i++) {
            // 尝试所有可能的字母
            for (char c = 'A'; c <= 'Z'; c++) {
                if (c != word.charAt(i)) {
                    // 创建新单词
                    StringBuilder newWord = new StringBuilder(word);
                    newWord.setCharAt(i, c);
                    String neighbor = newWord.toString();

                    // 检查是否是有效的单词
                    if (dictionary.isValidWord(neighbor)) {
                        neighbors.add(neighbor);
                    }
                }
            }
        }

        return neighbors;
    }

    // Getters and Setters

    public String getStartWord() {
        return startWord;
    }

    public String getTargetWord() {
        return targetWord;
    }

    public List<String> getAttempts() {
        return new ArrayList<>(attempts);
    }

    public List<String[]> getFeedbacks() {
        return new ArrayList<>(feedbacks);
    }

    public boolean isGameWon() {
        return gameWon;
    }

    public boolean isShowErrorMessage() {
        return showErrorMessage;
    }

    public void setShowErrorMessage(boolean showErrorMessage) {
        this.showErrorMessage = showErrorMessage;
        setChanged();
        notifyObservers();
    }

    public boolean isShowPath() {
        return showPath;
    }

    public void setShowPath(boolean showPath) {
        this.showPath = showPath;
        setChanged();
        notifyObservers();
    }

    public boolean isUseRandomWords() {
        return useRandomWords;
    }

    public void setUseRandomWords(boolean useRandomWords) {
        this.useRandomWords = useRandomWords;
        initGame();  // 重新初始化游戏以应用新设置
    }

    public int getAttemptsCount() {
        return attempts.size();
    }

    public Dictionary getDictionary() {
        return dictionary;
    }

    /**
     * Get the last notification argument
     * @return the last notification argument
     */
    public Object getLastNotificationArg() {
        return lastNotificationArg;
    }

    /**
     * Set the start word for the game
     * @param startWord the new start word
     */
    public void setStartWord(String startWord) {
        // 验证输入
        if (startWord == null || startWord.length() != WORD_LENGTH) {
            throw new IllegalArgumentException("Start word must be exactly " + WORD_LENGTH + " characters long");
        }

        // 转换为大写
        this.startWord = startWord.toUpperCase();

        // 确保单词在字典中
        if (!dictionary.isValidWord(this.startWord)) {
            throw new IllegalArgumentException("Start word must be a valid dictionary word");
        }

        // 如果目标单词与新的起始单词相同，重新选择目标单词
        if (this.startWord.equals(targetWord)) {
            List<String> fourLetterWords = dictionary.getWordsByLength(WORD_LENGTH);
            if (fourLetterWords.size() >= 2) {
                Random random = new Random();
                do {
                    targetWord = fourLetterWords.get(random.nextInt(fourLetterWords.size()));
                } while (targetWord.equals(this.startWord));
            } else {
                // 如果没有足够的单词，使用默认目标单词
                targetWord = DEFAULT_TARGET_WORD;
            }
        }

        // 重置游戏状态
        initGame();
    }

    /**
     * Set the target word for the game
     * @param targetWord the new target word
     */
    public void setTargetWord(String targetWord) {
        // 验证输入
        if (targetWord == null || targetWord.length() != WORD_LENGTH) {
            throw new IllegalArgumentException("Target word must be exactly " + WORD_LENGTH + " characters long");
        }

        // 转换为大写
        this.targetWord = targetWord.toUpperCase();

        // 确保单词在字典中
        if (!dictionary.isValidWord(this.targetWord)) {
            throw new IllegalArgumentException("Target word must be a valid dictionary word");
        }

        // 如果起始单词与新的目标单词相同，重新选择起始单词
        if (startWord.equals(this.targetWord)) {
            List<String> fourLetterWords = dictionary.getWordsByLength(WORD_LENGTH);
            if (fourLetterWords.size() >= 2) {
                Random random = new Random();
                do {
                    startWord = fourLetterWords.get(random.nextInt(fourLetterWords.size()));
                } while (startWord.equals(this.targetWord));
            } else {
                // 如果没有足够的单词，使用默认起始单词
                startWord = DEFAULT_START_WORD;
            }
        }

        // 重置游戏状态
        initGame();
    }
}